package com.lmm.rpc.client.processor;

import com.lmm.rpc.client.annotation.RpcAutowired;
import com.lmm.rpc.client.autoconfig.RpcClientProperties;
import com.lmm.rpc.core.cluster.ILoadBalancer;
import com.lmm.rpc.core.proxy.ProxyFactory;
import com.lmm.rpc.core.proxy.invocation.ClientStubInvocationHandler;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @title: RpcClientProcessor
 * @Description: 利用spring bean的生命周期实现代理增强
 * @Author Lmm
 * @Date: 2022/10/8 16:40
 * @Version 1.0
 */
public class RpcClientProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {
    //代理对象缓存
    private final Map<String, Object> objectCache = new ConcurrentHashMap<>();
    //代理工厂
    private ProxyFactory proxyFactory;

    //全局配置
    private RpcClientProperties properties;

    //spring上下文applicationContext
    private ApplicationContext applicationContext;

    public RpcClientProcessor(ProxyFactory proxyFactory,RpcClientProperties properties){
        this.proxyFactory = proxyFactory;
        this.properties = properties;
    }

    /**
     * 处理需要被代理的对象
     * */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        //遍历每一个bean
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
            String beanClassName = beanDefinition.getBeanClassName();
            if (beanClassName != null){
                Class<?> clazz = ClassUtils.resolveClassName(beanClassName, this.getClass().getClassLoader());
                ReflectionUtils.doWithFields(clazz,field -> {
                    //遍历每一个属性  判断是否是我们的注解修饰的
                    RpcAutowired rpcAutowired = AnnotationUtils.getAnnotation(field, RpcAutowired.class);
                    if (rpcAutowired != null){
                        Object bean = applicationContext.getBean(clazz);
                        field.setAccessible(true);
                        String serviceInterface = field.getType().getName();
                        //先查缓存
                        if (objectCache.containsKey(field.getType().getName())){
                            ReflectionUtils.setField(field,bean,objectCache.get(serviceInterface));
                        }else {
                            ClientStubInvocationHandler handler = new ClientStubInvocationHandler();
                            initProperties(rpcAutowired,handler,serviceInterface);
                            Object proxyBean = proxyFactory.getProxy(field.getType(), handler, field.getType().getClassLoader());
                            objectCache.put(serviceInterface,proxyBean);
                            //把代理对象复制给field
                            ReflectionUtils.setField(field,bean,proxyBean);
                        }
                    }
                });
            }
        }
    }

    /**
     * 处理注解上的属性：初始化
     * 局部大于全局配置
     * */
    private void initProperties(RpcAutowired rpcAutowired, ClientStubInvocationHandler handler, String serviceInterface) {

        //1、处理全局配置
        ILoadBalancer iLoadBalancer = null;
        String loadBalanceName = rpcAutowired.iLoadBalancer();
        if (loadBalanceName != null && loadBalanceName.trim().length() > 0){
             iLoadBalancer = (ILoadBalancer)applicationContext.getBean(loadBalanceName);
        }
        if (iLoadBalancer == null){
            iLoadBalancer = (ILoadBalancer)applicationContext.getBean(properties.getLoadBalancer());
        }
        handler.setILoadBalancer(iLoadBalancer);
        handler.setZkPath(properties.getZkPath());


        //2、处理局部配置
        handler.setRetryRequest(rpcAutowired.retryRequest());
        handler.setRetryTimes(rpcAutowired.retryTimes());
        handler.setTimeBetweenEvictionRunsMillis(rpcAutowired.timeBetweenEvictionRunsMillis());
        handler.setTestWhileIdle(rpcAutowired.testWhileIdle());
        handler.setTestOnCreate(rpcAutowired.testOnCreate());
        handler.setTestOnReturn(rpcAutowired.testOnReturn());
        handler.setTestOnBorrow(rpcAutowired.testOnBorrow());
        handler.setSoftMinEvictableIdleTimeMillis(rpcAutowired.softMinEvictableIdleTimeMillis());
        handler.setRemoveAbandonedTimeout(rpcAutowired.removeAbandonedTimeout());
        handler.setRemoveAbandonedOnMaintenance(rpcAutowired.removeAbandonedOnMaintenance());
        handler.setRemoveAbandonedOnBorrow(rpcAutowired.removeAbandonedOnBorrow());
        handler.setNumTestsPerEvictionRun(rpcAutowired.numTestsPerEvictionRun());
        handler.setMinIdle(rpcAutowired.minIdle());
        handler.setMaxIdle(rpcAutowired.maxIdle());
        handler.setMinEvictableIdleTimeMillis(rpcAutowired.minEvictableIdleTimeMillis());
        handler.setMaxWaitMillis(rpcAutowired.maxWaitMillis());
        handler.setMaxTotal(rpcAutowired.maxTotal());
        handler.setLifo(rpcAutowired.lifo());
        handler.setFairness(rpcAutowired.fairness());
        handler.setServiceInterface(serviceInterface);
        handler.setServerIpPorts(rpcAutowired.serverIpPorts());

        //初始化注册中心 拉取服务
        handler.afterProperties();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
